use std::fs;
use std::sync::{Arc, LazyLock};

use arc_swap::{ArcSwapAny, ArcSwapOption};
use log::debug;
use serde::{Deserialize, Serialize};

use crate::error::*;
use crate::listener::conf::ListenerConf;
use crate::utils::file::file_name;

#[derive(Default, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(default)]
pub struct ListenersConf {
    pub listeners: Vec<ListenerConf>,
}

#[allow(dead_code)]
impl ListenersConf {
    pub fn load_from_yaml(path: &str) -> Result<Self> {
        let conf_str = fs::read_to_string(path).if_err(
            ErrorType::ParseError,
            format!("Unable to read conf file from {path}"),
        )?;
        debug!("ListenersConf file read from {}", file_name(path));
        Self::from_yaml(&conf_str)
    }

    fn from_yaml(conf_str: &str) -> Result<Self> {
        let conf: ListenersConf = serde_yaml::from_str(conf_str)
            .if_err(ErrorType::ParseError, "Unable to parse linker conf")?;
        conf.validate()
    }

    fn validate(mut self) -> Result<Self> {
        // TODO: check validate of listeners conf
        for v in self.listeners.iter_mut() {
            v.validate()
                .if_err(ErrorType::InvalidError, "invalid listener conf")?;
        }

        Ok(self)
    }
}

static LISTENERS_CONF: LazyLock<ArcSwapOption<ListenersConf>> =
    LazyLock::new(|| ArcSwapAny::new(None));

pub fn set_listeners_conf(conf: ListenersConf) {
    LISTENERS_CONF.store(Some(Arc::new(conf)));
}

#[allow(dead_code)]
pub fn get_listeners_conf() -> Arc<ListenersConf> {
    LISTENERS_CONF.load().clone().unwrap()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_listeners_conf_parse() {
        let conf_str = r#"
            listeners:
                - name: "listener_1"
                  address: "127.0.0.1:80"
                - name: "listener_2"
                  address: "[::]:80"
        "#;

        let listeners = ListenersConf::from_yaml(conf_str).unwrap();
        println!("{:#?}", listeners);
    }
}
